#include <iostream>
#include <memory>
#include <queue>
#include <vector>

#include "Log.hpp"
#include "MyMute.hpp"
#include "myCond.hpp"
#include "Thread.hpp"

namespace ThreadPoolModule
{
    using namespace MyCondModule;
    using namespace MyLogModule;
    using namespace MyMutexModule;
    using namespace MyThreadModule;

    static const int default_count = 3;

    using thread_t = shared_ptr<MyThread>;

    void DefaultTest()
    {
        while (true)
        {
            LOG(NORMAL) << "测试线程的执行方法";
            sleep(1);
        }
    }

    template <class T>
    class ThreadPool
    {
    private:
        queue<T> _task_q;          // 任务队列
        vector<thread_t> _threads; // 管理线程的结构
        int _threadCount;          // 线程的数量
        int _wait_num;
        Mutex _lock;
        Cond _cond;
        bool _isRunning;

        static ThreadPool *_instance;
        static Mutex _ins_lock;

    private:
        bool isEmpty()
        {
            return _task_q.empty();
        }

        void HandleTask(std::string name)
        {
            // LOG(NORMAL) << name << "进入HandleTask方法";
            // 线程要一直做该任务
            while (true)
            {
                // 1. 拿任务
                T t;
                {
                    LockGuard lockguard(_lock);
                    // 任务队列为空，线程池没退，则进程必须等
                    while (isEmpty() && _isRunning)
                    {
                        _wait_num++;
                        _cond.wait(_lock);
                        _wait_num--;
                    }
                    // 任务队列为空，线程池退了，则进程自己退出
                    if (isEmpty() && !_isRunning)
                        break;
                    // 任务队列不为空，线程池退/没退，线程都执行任务完任务
                    t = _task_q.front();
                    _task_q.pop();
                }

                // 2. 处理任务
                t();
            }
        }
        // 禁止拷贝构造
        ThreadPool(const ThreadPool &tp) = delete;
        const ThreadPool &operator=(const ThreadPool &tp) = delete;

        // 将构造函数私有
        ThreadPool(int count = default_count)
            : _threadCount(count), _wait_num(0), _isRunning(false)
        {
            // 构建线程对象
            for (int i = 0; i < _threadCount; i++)
            {
                // 构造MyThread时，将HandleTask方法与其绑定，传递this指针是为了访问它。
                // _threads.push_back(make_shared<MyThread>(bind(&ThreadPool::HandleTask, this, std::placeholders::_1)));
                _threads.push_back(make_shared<MyThread>([this](std::string name)
                                                         { this->HandleTask(name); }));

                LOG(NORMAL) << "构建线程对象" << _threads.back()->name() << "...成功";
            }
        }

    public:
        static ThreadPool<T> *GetInstance()
        {
            //为避免不必要的锁竞争，使用双if判断
            if (_instance == nullptr)
            {
                LockGuard lockguard(_ins_lock); //线程安全的线程池
                if (_instance == nullptr)
                {
                    LOG(NORMAL) << "创建单例线程池..";
                    //懒汉模式
                    _instance = new ThreadPool<T>();
                    _instance->Start();
                }
            }
            return _instance;
        }

        ~ThreadPool()
        {
        }

        void Start()
        {
            if (_isRunning)
                return;
            _isRunning = true; // 线程池运行标记

            // 启动线程
            for (auto &thread_ptr : _threads)
            {
                thread_ptr->create();
                LOG(NORMAL) << "启动线程" << thread_ptr->name() << "...成功";
            }
        }

        void Wait()
        {
            // 等待线程
            for (auto &thread_ptr : _threads)
            {
                thread_ptr->join();
                LOG(NORMAL) << "等待线程" << thread_ptr->name() << "...成功";
            }
        }

        void Stop()
        {
            LockGuard lockguard(_lock);
            if (_isRunning)
            {
                _isRunning = false;

                // 1.不能再次放任务了--标记位
                // 2.让线程自己结束
                if (_wait_num)
                    _cond.signalAll(); // 唤醒所有线程
                // 3.历史任务都要被执行完了
            }

            LOG(NORMAL) << "线程池stop..";
        }

        void Push(T in)
        {
            LockGuard lockguard(_lock);
            if (!_isRunning)
                return;
            _task_q.push(in);
            if (_wait_num)
                _cond.signal();
        }
    };

    template<class T>
    ThreadPool<T>* ThreadPool<T>::_instance = nullptr;

    template<class T>
    Mutex ThreadPool<T>::_ins_lock;

} // namespace ThreadPoolModule
